package im.oen.boot.common.utils;

/**
 * 字节操作工具
 *
 * @author Kevin.Xu
 */
public class ByteUtil {
    public static final byte BIT = 0x01;

    private static final int BIT_LEN_BYTE = 8;
    private static final int BYTE_LEN_SHORT = 2;
    private static final int BYTE_LEN_INT = 4;

    /**
     * 将二进制转换为十六进制字符输出
     *
     * @param bytes 二进制
     * @return 十六进制字符串
     */
    public static String toHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    /**
     * 将十六进制转换为字节数组
     *
     * @param hexStr 十六进制字符串
     * @return 二进制数据
     */
    public static byte[] hexToBytes(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }

        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * 将Byte数据的指定位置设置为true或false
     *
     * @param b     数据
     * @param value 需要设置的值
     * @param pos   位置(不能操作BIT的长度 8)
     * @return 设置后的Byte数据
     */
    public static byte setBitInfo(byte b, boolean value, int pos) {
        if (pos >= BIT_LEN_BYTE || pos < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        byte tmp = (byte) (BIT << pos);
        return (byte) (value ? (b | tmp) : (b & ~tmp));
    }

    /**
     * 将Byte数据的指定位置设置为True
     *
     * @param b   数据
     * @param pos 位置
     * @return 设置后的Byte数据
     */
    public static byte setTrue(byte b, int pos) {
        return setBitInfo(b, true, pos);
    }

    /**
     * 将Byte数据的指定位置设置为False
     *
     * @param b   数据
     * @param pos 位置
     * @return 设置后的Byte数据
     */
    public static byte setFalse(byte b, int pos) {
        return setBitInfo(b, false, pos);
    }

    /**
     * 检查Byte数据的指定位置的数据
     *
     * @param b   数据
     * @param pos 位置
     * @return 结果:True或False
     */
    public static boolean check(byte b, int pos) {
        if (pos >= BIT_LEN_BYTE || pos < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        byte tmp = (byte) (BIT << pos);
        return ((b & tmp) == tmp);
    }

    /**
     * 短数字转换为2位的字节数组
     *
     * @param num 数字
     * @return 字节数组
     */
    public static byte[] short2bytes(short num) {
        return new byte[]{(byte) (num >> 8), (byte) (num >> 0)};
    }

    /**
     * 2位的字节数组转换为短数字
     *
     * @param bytes 2位字节数组
     * @return 短数字
     */
    public static short bytes2short(byte[] bytes) {
        if (bytes.length != BYTE_LEN_SHORT) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return (short) (bytes[0] << 8 | bytes[1] & 0xff);
    }

    /**
     * 数字转换为4位字节数组
     *
     * @param num 数字
     * @return 4位字节数组
     */
    public static byte[] int2bytes(int num) {
        return new byte[]{(byte) ((num >> 24) & 0xFF), (byte) ((num >> 16) & 0xFF), (byte) ((num >> 8) & 0xFF), (byte) (num & 0xFF)};
    }

    public static byte[] long2bytes(long num) {
        byte[] bytes = new byte[8];
        for (int i = 7; i >= 0; --i) {
            bytes[i] = (byte) (num & 0xFF);
            num = num >> 8;
        }
        return bytes;
    }

    /**
     * 4位字节数组转换为数字
     *
     * @param bytes 4位字节数组
     * @return 数字
     */
    public static int bytes2int(byte[] bytes) {
        if (bytes.length != BYTE_LEN_INT) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return bytes[3] & 0xFF | (bytes[2] & 0xFF) << 8 | (bytes[1] & 0xFF) << 16 | (bytes[0] & 0xFF) << 24;
    }

    /**
     * 循环对每个字节做异或操作
     *
     * @param bytes 字节数组
     * @param b     异或字节
     * @return 异或后的字节数组
     */
    public static byte[] xor(byte[] bytes, byte b) {
        byte[] result = new byte[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            result[i] = (byte) (bytes[i] ^ b);
        }
        return result;
    }

    /**
     * 从字节数组中提取一段数组
     *
     * @param source 源数组
     * @param start  开始位置
     * @param length 提取长度
     * @return 新数组
     */
    public static byte[] fetch(byte[] source, int start, int length) {
        int end = start + length;
        if (end > source.length) {
            return null;
        }
        byte[] result = new byte[length];

        int idx = 0;
        for (int i = start; i < end; i++) {
            result[idx] = source[i];
            idx++;
        }
        return result;
    }

    /**
     * 对多个字节数组进行合并
     *
     * @param bytes 多个字节数组
     * @return 合并后的字节数组
     */
    public static byte[] merge(byte[]... bytes) {
        if (bytes.length < 1) {
            return null;
        }

        if (bytes.length == 1) {
            return bytes[0];
        }

        int length = 0;
        for (byte[] bs : bytes) {
            length += bs.length;
        }

        int desPos = 0;
        byte[] result = new byte[length];
        for (int i = 0; i < bytes.length; i++) {
            byte[] source = bytes[i];
            desPos += (i == 0 ? 0 : bytes[i - 1].length);
            System.arraycopy(source, 0, result, desPos, source.length);
        }
        return result;
    }
}
